home *** CD-ROM | disk | FTP | other *** search
/ The Arsenal Files 4 / The Arsenal Files 4 (Arsenal Computer).ISO / casm / au116-as.exe / DUPES.CPP < prev    next >
C/C++ Source or Header  |  1994-11-18  |  12KB  |  456 lines

  1. // DUPES.CPP                                 1          1    6666
  2. // Dave Harris                                11         11   6
  3. // Compiled using Borland C++ ver 3.1       1 1        1 1   6666
  4. // 03-03-94                                  1     ..   1   6   6
  5. //                                           11111 .. 11111  666
  6. ////////////////////////////////////////////////////////////////////////
  7.  
  8. #include "au.hpp"
  9.  
  10. #define PROGRAM "DUPES"  // Name of module
  11.  
  12. typedef struct
  13. {
  14.     char arcFile[80];
  15.     char filename[FILE_SIZE];
  16.     unsigned long crc;
  17.     long size;
  18.     long next;                 /* next file record */
  19.     unsigned short used;     /* used flag */
  20. } FILE_CONT;
  21.  
  22. typedef struct
  23. {
  24.     long first;
  25.     long last;
  26. } HASH;
  27.  
  28. #define HASH_SLOTS 1024
  29.  
  30. /*********************************************************************/
  31.  
  32. typedef struct
  33. {
  34.     char do_arcs;              // do arced files or not */
  35.     HASH *hash;
  36.     long last_record;
  37.     long number_inside_processed;
  38.     long size_thresh;
  39.     char data_file_name[FLENGTH];
  40.     HANDLE data_handle;
  41.     char log_file_name[FLENGTH];
  42.     HANDLE log_handle;
  43.     BYTE keep_data_file;
  44.     BYTE use_32;
  45.     BYTE verbose;
  46.     unsigned short used;      // Used number to use
  47. } DUPES_INFO;
  48.  
  49. #define HASH_TABLE_SIZE (sizeof(HASH) * HASH_SLOTS)
  50.  
  51. /*░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░*/
  52. static void dupes_log(AU *au, char *format, ...)
  53. {
  54.     DUPES_INFO *in = (DUPES_INFO *)au->info;
  55.     va_list plist;
  56.     char string[200];
  57.  
  58.     va_start(plist, format);
  59.     vsprintf(string, format, plist);
  60.     va_end(plist);
  61.  
  62.     if (in->log_file_name[0] != '\0')
  63.     {
  64.         in->log_handle.write_raw(string, strlen(string));
  65.     }
  66.     return;
  67. }
  68.  
  69. /*░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░*/
  70. static void read_hash_table(AU *au)
  71. {
  72.     DUPES_INFO *in = (DUPES_INFO *)au->info;
  73.     long pos;
  74.  
  75.     in->data_handle.seek_raw(0L, SEEK_SET);
  76.     if (in->data_handle.read_raw(in->hash, HASH_TABLE_SIZE) != HASH_TABLE_SIZE)
  77.     {
  78.         au_printf_error(au, "\nRead Error");
  79.         exit(1);
  80.     }
  81.     if (in->data_handle.read_raw(&in->used, 2) != 2)
  82.     {
  83.         au_printf_error(au, "\nRead Error");
  84.         exit(1);
  85.     }
  86.     in->used++;
  87.  
  88.     pos = in->data_handle.file_length();
  89.     in->last_record = (pos - HASH_TABLE_SIZE - 2)/sizeof(FILE_CONT);
  90. }
  91. /*░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░*/
  92. static void write_hash_table(AU *au)
  93. {
  94.     DUPES_INFO *in = (DUPES_INFO *)au->info;
  95.  
  96.     in->data_handle.seek_raw(0L, SEEK_SET);
  97.     if (in->data_handle.write_raw(in->hash, HASH_TABLE_SIZE) != HASH_TABLE_SIZE)
  98.     {
  99.         au_printf_error(au, "\nWrite Error");
  100.         exit(1);
  101.     }
  102.     if (in->data_handle.write_raw(&in->used, 2) != 2)
  103.     {
  104.         au_printf_error(au, "\nRead Error");
  105.         exit(1);
  106.     }
  107. }
  108. /*░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░*/
  109. static void read_data_struct(AU *au, FILE_CONT *contents, long record)
  110. {
  111.     DUPES_INFO *in = (DUPES_INFO *)au->info;
  112.  
  113.     in->data_handle.seek_raw(HASH_TABLE_SIZE + 2 + sizeof(FILE_CONT)*(record-1), SEEK_SET);
  114.     in->data_handle.read_raw(contents, sizeof(FILE_CONT));
  115. }
  116. /*░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░*/
  117. static void write_data_struct(AU *au, FILE_CONT *contents,long record)
  118. {
  119.     DUPES_INFO *in = (DUPES_INFO *)au->info;
  120.  
  121.     in->data_handle.seek_raw(HASH_TABLE_SIZE + 2 + sizeof(FILE_CONT)*(record-1), SEEK_SET);
  122.     if (in->data_handle.write_raw(contents, sizeof(FILE_CONT)) != sizeof(FILE_CONT))
  123.     {
  124.         au_printf_error(au, "\nWrite Error");
  125.         exit(1);
  126.     }
  127. }
  128. /*░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░*/
  129. static BYTE add_to_list(AU *au, char *arcFile, char *filename, unsigned long crc, long size)
  130. {
  131.     FILE_CONT temp;
  132.     long end;
  133.     unsigned int hash_code;
  134.     DUPES_INFO *in = (DUPES_INFO *)au->info;
  135.  
  136.     if (size < in->size_thresh)
  137.         return FALSE;
  138.     if (strlen(filename) >= FILE_SIZE)
  139.         filename[FILE_SIZE-1] = '\0';
  140.     strcpy(temp.arcFile, arcFile);
  141.     strcpy(temp.filename, filename);
  142.     temp.crc = crc;
  143.     temp.size = size;
  144.     temp.next = 0L;
  145.  
  146.     hash_code = crc % HASH_SLOTS;
  147.     in->last_record++;
  148.     if (in->hash[hash_code].first == 0)
  149.         in->hash[hash_code].first = in->hash[hash_code].last = in->last_record;
  150.     else                   /* thread the previous */
  151.     {
  152.         FILE_CONT last;
  153.         read_data_struct(au, &last, in->hash[hash_code].last);
  154.         last.next = in->last_record;
  155.         write_data_struct(au, &last, in->hash[hash_code].last);
  156.         in->hash[hash_code].last = in->last_record;
  157.     }
  158.     write_data_struct(au, &temp, in->last_record);
  159.     return TRUE;
  160. }
  161. /*░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░*/
  162. static BYTE dupes_one(AU *au, char *file_name, ARC_HANDLE *arc_handle)
  163. {
  164.     ARC_RECORD record;
  165.     int ret_code;
  166.     BYTE returnCode = FALSE;
  167.     char string[FLENGTH];
  168.     DUPES_INFO *in = (DUPES_INFO *)au->info;
  169.  
  170.     for (;;)
  171.     {
  172.         ret_code = arc_handle->get_record(au, &record);
  173.         if (ret_code == EOF)
  174.             break;
  175.         else if (ret_code == -2)
  176.         {
  177.             add_to_bad_list(au, au->source_directory, file_name);
  178.             return FALSE;
  179.         }
  180.         else if (ret_code == -3)
  181.             return FALSE;
  182.  
  183.         build_fname(string, au->source_directory, file_name);
  184.         if (add_to_list(au, string, record.name, record.crc, record.unpacked_size))
  185.             returnCode = TRUE;
  186.         in->number_inside_processed++;
  187.     }
  188.     return returnCode;
  189. }
  190. /*░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░*/
  191. static int dupes(AU *au, char *file_name)
  192. {
  193.     ARC_HANDLE arc_handle;
  194.     char string[FLENGTH];
  195.     struct ffblk ffblk;
  196.     DUPES_INFO *in = (DUPES_INFO *)au->info;
  197.     BYTE processed = FALSE;
  198.  
  199.     check_for_key();
  200.  
  201.     if (in->do_arcs != OFF)
  202.     {
  203.         arc_handle.init(au, file_name);
  204.         if (arc_handle.type > 0 && au->package[arc_handle.type].crc != 0)
  205.         {
  206.             processed = dupes_one(au, file_name, &arc_handle);
  207.         }
  208.         arc_handle.deinit(au);
  209.     }
  210.  
  211.     if (in->do_arcs != ONLY)
  212.     {
  213.         /* Place the archive itself in the list */
  214.         build_fname(string, au->source_directory, file_name);
  215.  
  216.         findfirst(file_name, &ffblk, 0);
  217.         if (in->use_32)
  218.             processed |=
  219.               add_to_list(au, string, "", crc32(au, file_name), ffblk.ff_fsize);
  220.         else
  221.             processed |=
  222.               add_to_list(au, string, "", crc16(au, file_name), ffblk.ff_fsize);
  223.     }
  224.     if (processed)
  225.     {
  226.         au->number_processed++;
  227.         if (in->verbose)
  228.             au_printf(au, "@?6Processed @?1%s@?H\n", file_name);
  229.     }
  230.  
  231.     return 0;
  232. }
  233. /*░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░*/
  234. static BYTE parse_comm_line(AU *au, char option, char *cur_argv,
  235.                             PARSE_TYPE type)
  236. {
  237.     DUPES_INFO *in = (DUPES_INFO *)au->info;
  238.  
  239.     switch (type)
  240.     {
  241.     case PARSE_SINGLE_OPTION:
  242.         if (option == '3')
  243.         {
  244.             in->use_32 = TRUE;
  245.             return TRUE;
  246.         }
  247.         if (option == '1')
  248.         {
  249.             in->use_32 = FALSE;
  250.             return TRUE;
  251.         }
  252.         else if (option == 'V')
  253.         {
  254.             in->verbose = TRUE;
  255.             return TRUE;
  256.         }
  257.         return FALSE;
  258.     case PARSE_PARAM_OPTION:
  259.         switch (option)
  260.         {
  261.         case 'W':
  262.             strcpy(au->dest_directory, cur_argv);
  263.             break;
  264.         case 'A':                 /* Smart mode on/off/always */
  265.             in->do_arcs = get_value(au, OFF | ON | ONLY);
  266.             break;
  267.         case 'D':
  268.             strcpy(in->data_file_name, cur_argv);
  269.             in->keep_data_file = TRUE;
  270.             break;
  271.         case 'L':
  272.             strcpy(in->log_file_name, cur_argv);
  273.             break;
  274.         case 'T':
  275.             in->size_thresh = atol(cur_argv);
  276.             break;
  277.         case '?':
  278.             au_standard_opt_header(au, "DUpes",
  279.                 "@?3-16@?H             use 16 bit CRCs for non-arc files\n"
  280.                 "@?3-32@?H             use 32 bit CRCs for non-arc files (default)\n"
  281.                 "@?3-A@?Hon|off|only   process Archive files\n"
  282.                 "@?3-D@?H<file>        Data file.  If unspecified, a temp file is used and deleted\n"
  283.                 "@?3-L@?H<file>        Log file.  Contains listing of duplicates\n"
  284.                 "@?3-T@?Hn             size Threshold\n"
  285.                 "@?3-V@?H              Verbose listing of files as processed\n"
  286.                 "@?3-W@?H<path>        Work directory\n");
  287.             exit(0);
  288.         default:
  289.             au_invalid_option(au, PROGRAM, option);
  290.         }
  291.         return TRUE;
  292.     }
  293.     return FALSE;
  294. }
  295. /*░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░*/
  296. static void print_results(AU *au)
  297. {
  298.     FILE_CONT temp,temp2;
  299.     int first = TRUE;
  300.     long rec;
  301.     DUPES_INFO *in = (DUPES_INFO *)au->info;
  302.  
  303.     au_printf_c(au, 15, "\nDuplicate Files:\n\n");
  304.  
  305.     for (int i=0; i<HASH_SLOTS; i++)
  306.     {
  307.         if (in->hash[i].first != 0)
  308.         {
  309.             read_data_struct(au, &temp, in->hash[i].first);
  310.             while (temp.next != 0)
  311.             {
  312.                 if (temp.next > in->hash[i].last)
  313.                 {
  314.                     au_printf_error(au, "Corrupt data file in hash thread %d\n", i);
  315.                     break;
  316.                 }
  317.                 if (temp.used != in->used)
  318.                 {
  319.                 rec = temp.next;
  320.                 read_data_struct(au, &temp2, rec);
  321.                 for(EVER)
  322.                 {
  323.                     if (temp2.next > in->hash[i].last)
  324.                     {
  325.                         au_printf_error(au, "Corrupt data file in hash thread %d\n", i);
  326.                         break;
  327.                     }
  328.                     if (temp.crc == temp2.crc && temp.size == temp2.size &&
  329.                         temp2.used != in->used)
  330.                     {
  331.                         if (first)
  332.                         {
  333.                             if (temp.filename[0] != '\0')
  334.                             {
  335.                                 au_printf(au, "(@?B%s@?H inside @?1%s@?H)", temp.filename, temp.arcFile);
  336.                                 dupes_log(au, "(%s inside %s)", temp.filename, temp.arcFile);
  337.                             }
  338.                             else
  339.                             {
  340.                                 au_printf(au, "@?1%s@?H", temp.arcFile);
  341.                                 dupes_log(au, "%s", temp.arcFile);
  342.                             }
  343.                             au_printf(au, "\n");
  344.                             dupes_log(au, "\n");
  345.                             first = FALSE;
  346.                         }
  347.                         au_printf(au, "     ");
  348.                         dupes_log(au, "     ");
  349.  
  350.                         if (temp2.filename[0] != '\0')
  351.                         {
  352.                             au_printf(au, "(@?C%s@?H inside @?2%s@?H)", temp2.filename, temp2.arcFile);
  353.                             dupes_log(au, "(%s inside %s)", temp2.filename, temp2.arcFile);
  354.                         }
  355.                         else
  356.                         {
  357.                             au_printf(au, "@?2%s@?H", temp2.arcFile);
  358.                             dupes_log(au, "%s", temp2.arcFile);
  359.                         }
  360.                         au_printf(au, "\n");
  361.                         dupes_log(au, "\n");
  362.                         temp2.used = in->used;
  363.                         write_data_struct(au, &temp2, rec);
  364.                     }
  365.                     if (temp2.next == 0)
  366.                         break;
  367.                     else
  368.                     {
  369.                         rec = temp2.next;
  370.                         read_data_struct(au, &temp2, rec);
  371.                     }
  372.                 }
  373.                 }
  374.                 read_data_struct(au, &temp, temp.next);
  375.                 first = TRUE;
  376.             }
  377.         }
  378.     }
  379. }
  380. /*░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░*/
  381. static void end_program(void)
  382. {
  383.     DUPES_INFO *in = (DUPES_INFO *)glob_au->info;
  384.  
  385.     if (in->data_handle.is_open())
  386.     {
  387.         write_hash_table(glob_au);
  388.         in->data_handle.close();
  389.         if (!in->keep_data_file)
  390.             unlink(in->data_file_name);
  391.     }
  392.     if (in->log_file_name[0] != '\0')
  393.     {
  394.         in->log_handle.close();
  395.     }
  396.     if (in->hash != NULL)
  397.         free(in->hash);
  398.     return;
  399. }
  400. /*░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░*/
  401. int main_dupes(AU *au, int argc, char *argv[])
  402. {
  403.     DUPES_INFO *in;
  404.     long space_required;
  405.  
  406.     in = new DUPES_INFO;
  407.  
  408.     memset(in, '\0', sizeof(DUPES_INFO));
  409.     au->info = in;
  410.     in->do_arcs=ON;
  411.     in->size_thresh=1;
  412.     in->use_32 = TRUE;
  413.     in->used = 1;
  414.  
  415.     ReadGlobalCFGInfo(au, au->cfg_file, PROGRAM, NULL);
  416.     generic_parse_comm_line(au, argc, argv, parse_comm_line);
  417.  
  418.     atexit(end_program);
  419.  
  420.     in->hash = (HASH *)au_calloc(au, sizeof(HASH), HASH_SLOTS);
  421.  
  422.     if (in->data_file_name[0] == '\0')
  423.         build_fname(in->data_file_name, au->dest_directory, "dupes94.dat");
  424.  
  425.     if (in->keep_data_file && access(in->data_file_name, 0x00) == 0)
  426.     {
  427.         in->data_handle.open(au, in->data_file_name, O_BINARY | O_RDWR);
  428.         read_hash_table(au);
  429.     }
  430.     else
  431.     {
  432.         _fmode = O_BINARY;
  433.         in->data_handle.create(in->data_file_name, S_IREAD|S_IWRITE);
  434.         _fmode = O_TEXT;
  435.     }
  436.     if (in->log_file_name[0] != '\0')
  437.     {
  438.         in->log_handle.open(au, in->log_file_name, O_CREAT|O_WRONLY|O_TEXT|O_APPEND);
  439.     }
  440.  
  441.     process_files(au, dupes);
  442.     print_results(au);
  443.     space_required = in->data_handle.file_length();
  444.  
  445.     if (!au->no_extra)
  446.     {
  447.         au_printf_c(au, 15, "\nFiles Processed = %d\n", au->number_processed);
  448.         au_printf_c(au, 15, "Files Inside Archives Processed = %ld\n",
  449.                in->number_inside_processed);
  450.         au_printf_c(au, 15, "Disk space required to hold results = %ld bytes\n", space_required);
  451.     }
  452.  
  453.     return 0;
  454. }
  455.  
  456.